package com.mx.recycleview.anytype

import android.content.Context
import android.view.ViewGroup
import android.widget.Space
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.mx.recycleview.base.BaseViewHolder
import kotlin.math.max

/**
 * @author 张孟雄
 *
 * 任意类型的适配器代理管理器
 *
 */
class TypeLayoutManager(context: Context) :
    GridLayoutManager(context, 1, VERTICAL, false) {
    private var recyclerView: RecyclerView? = null
    private val adaptList = ArrayList<BaseTypeAdapt<*>>()
    private var maxSpanCount = 0

    init {
        // 核心功能，通过调整SpanSize来控制每个Item需要占用一行中的几个位置
        super.setSpanSizeLookup(object : SpanSizeLookup() {
            override fun getSpanSize(position: Int): Int {
                val spanSize = getPositionAdapt(position)?.getSpanSize() ?: return maxSpanCount
                if (spanSize == 0) return maxSpanCount
                if (spanSize == Int.MAX_VALUE)
                    return maxSpanCount
                return maxSpanCount / spanSize
            }
        })
    }

    /**
     * 屏蔽该功能，不能修改
     */
    override fun setSpanSizeLookup(spanSizeLookup: SpanSizeLookup?) {
        //super.setSpanSizeLookup(spanSizeLookup)
    }

    /**
     * 所有的adapt数据监听
     * 当adapt有数据增减时，需要重新计算adapt的开始位置
     */
    private val adaptDataObserver = object : RecyclerView.AdapterDataObserver() {
        override fun onChanged() {
            notifyDataSetChanged()
        }

        override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
            notifyDataSetChanged()
        }

        override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) {
            notifyDataSetChanged()
        }
    }

    /**
     * 根据总位置获取对应的Item所在的Adapt
     */
    private fun getPositionAdapt(position: Int): BaseTypeAdapt<*>? {
        var start = 0
        adaptList.forEach { adapt ->
            val size = adapt.itemCount
            if (position >= start && position < size + start) {
                return adapt
            } else {
                start += size
            }
        }
        return null
    }

    /**
     * 绑定RecycleView
     */
    fun attachToRecycleView(recyclerView: RecyclerView) {
        this.recyclerView = recyclerView
        recyclerView.layoutManager = this
        recyclerView.adapter = delegateAdapt
    }

    /**
     * 设置适配器列表
     */
    fun setAdapts(list: List<BaseTypeAdapt<*>>) {
        adaptList.forEach { it.unregisterAdapterDataObserver(adaptDataObserver) }
        adaptList.clear()
        var maxSpan = 0
        var start = 0
        list.forEach { adapt ->
            try {
                adapt.unregisterAdapterDataObserver(adaptDataObserver)
            } catch (e: Exception) {
            }
            adapt.registerAdapterDataObserver(adaptDataObserver)
            if (adapt.getSpanSize() < Int.MAX_VALUE) {
                maxSpan = max(maxSpan, adapt.getSpanSize())
            }
            adapt.setStartIndex(start)
            start += adapt.itemCount
        }
        if (maxSpan == 0) maxSpan = 1
        maxSpanCount = maxSpan
        super.setSpanCount(maxSpan)

        adaptList.addAll(list)
        delegateAdapt.notifyDataSetChanged()
    }

    /**
     * 清理适配器
     */
    fun cleanAllAdapt() {
        adaptList.forEach { it.unregisterAdapterDataObserver(adaptDataObserver) }
        adaptList.clear()
        delegateAdapt.notifyDataSetChanged()
    }

    /**
     *
     */
    fun notifyDataSetChanged() {
        var maxSpan = 0
        var start = 0
        adaptList.forEach { adapt ->
            if (adapt.getSpanSize() < Int.MAX_VALUE) {
                maxSpan = max(maxSpan, adapt.getSpanSize())
            }
            adapt.setStartIndex(start)
            start += adapt.itemCount
        }
        if (maxSpan == 0) maxSpan = 1
        maxSpanCount = maxSpan
        super.setSpanCount(maxSpan)

        delegateAdapt.notifyDataSetChanged()
    }

    /**
     * 适配器总代理
     *
     */
    private val delegateAdapt = object : RecyclerView.Adapter<BaseViewHolder>() {
        override fun getItemCount(): Int {
            return adaptList.sumBy { it.itemCount }
        }

        override fun getItemViewType(position: Int): Int {
            return getPositionAdapt(position)?.getAdaptViewType() ?: VIEW_TYPE_NONE
        }

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
            if (viewType == VIEW_TYPE_NONE) return BaseViewHolder(Space(context), viewType)
            val holder = adaptList.firstOrNull { it.getAdaptViewType() == viewType }
                ?.createViewHolder(parent, viewType)
            return holder ?: BaseViewHolder(Space(context), viewType)
        }

        override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
            if (holder.viewType == VIEW_TYPE_NONE) return
            val adapt = getPositionAdapt(position)
            adapt?.onBindViewHolder(holder, position)
        }
    }

    companion object {
        const val VIEW_TYPE_NONE = -10000
    }
}